package com.bistu.caluculator

import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.widget.EditText
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
//import com.example.AndroidCalculator.R
import android.widget.Toast
import com.bistu.caluculator.R.menu
import java.lang.Math.pow
import java.math.BigDecimal
import java.util.*
import kotlin.math.log

class  Calculator : MainActivity(),View.OnClickListener {

    lateinit var editText: EditText

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)

        editText = findViewById(R.id.edit_text) as EditText
        val button1 = findViewById(R.id.button_1) as Button
        val button2 = findViewById(R.id.button_2) as Button
        val button3 = findViewById(R.id.button_3) as Button
        val button4 = findViewById(R.id.button_4) as Button
        val button5 = findViewById(R.id.button_5) as Button
        val button6 = findViewById(R.id.button_6) as Button
        val button7 = findViewById(R.id.button_7) as Button
        val button8 = findViewById(R.id.button_8) as Button
        val button9 = findViewById(R.id.button_9) as Button
        val button0 = findViewById(R.id.button_0) as Button
        val button_add = findViewById(R.id.button_add) as Button
        val button_sub = findViewById(R.id.button_sub) as Button
        val button_mul = findViewById(R.id.button_mul) as Button
        val button_div = findViewById(R.id.button_div) as Button
        val button_del = findViewById(R.id.button_del) as Button
        val button_neg = findViewById(R.id.button_neg) as Button
        val button_equ = findViewById(R.id.button_equ) as Button
        val button_pt = findViewById(R.id.button_pt) as Button
        val button_pc = findViewById(R.id.button_pc) as Button
        val button_fac = findViewById(R.id.button_fac) as Button
        val button_c = findViewById(R.id.button_c) as Button
        val button_root = findViewById(R.id.button_root) as Button
        //新增的log按钮
        val button_power = findViewById(R.id.button_power) as Button

        button0.setOnClickListener(this)
        button1.setOnClickListener(this)
        button2.setOnClickListener(this)
        button3.setOnClickListener(this)
        button4.setOnClickListener(this)
        button5.setOnClickListener(this)
        button6.setOnClickListener(this)
        button7.setOnClickListener(this)
        button8.setOnClickListener(this)
        button9.setOnClickListener(this)
        button_add.setOnClickListener(this)
        button_sub.setOnClickListener(this)
        button_mul.setOnClickListener(this)
        button_div.setOnClickListener(this)
        button_del.setOnClickListener(this)
        button_neg.setOnClickListener(this)
        button_equ.setOnClickListener(this)
        button_pt.setOnClickListener(this)
        button_pc.setOnClickListener(this)
        button_fac.setOnClickListener(this)
        button_c.setOnClickListener(this)
        button_root.setOnClickListener(this)
        //新增log的监听
        button_power.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        var et = editText.getText().toString()
        when (v?.getId()) {
            //pow**********
            R.id.button_power -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.' ||
                et[et.length - 1] == '^'
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            }

            else {
                val res = getResult()
                if (res.contains("Infinity")) { Toast.makeText(this@Calculator, "0 cannot be used as a divior!", Toast.LENGTH_SHORT).show()
                    editText.setText("0")
                } else {
                    var x = res.toDouble()
                    x = Math.pow(x,2.0)
                    var x2 = formatResult(x)
                    editText.setText(x2)
                }
               // editText.setText(et)
            }
            //***************************
            R.id.button_0 -> {
                if (et == "0") et = "0" else et += "0"
                editText.setText(et)
            }
            R.id.button_1 -> {
                if (et == "0") et = "1" else et += "1"
                editText.setText(et)
            }
            R.id.button_2 -> {
                if (et == "0") et = "2" else et += "2"
                editText.setText(et)
            }
            R.id.button_3 -> {
                if (et == "0") et = "3" else et += "3"
                editText.setText(et)
            }
            R.id.button_4 -> {
                if (et == "0") et = "4" else et += "4"
                editText.setText(et)
            }
            R.id.button_5 -> {
                if (et == "0") et = "5" else et += "5"
                editText.setText(et)
            }
            R.id.button_6 -> {
                if (et == "0") et = "6" else et += "6"
                editText.setText(et)
            }
            R.id.button_7 -> {
                if (et == "0") et = "7" else et += "7"
                editText.setText(et)
            }
            R.id.button_8 -> {
                if (et == "0") et = "8" else et += "8"
                editText.setText(et)
            }
            R.id.button_9 -> {
                if (et == "0") et = "9" else et += "9"
                editText.setText(et)
            }
            R.id.button_pt -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.' ||
                (!et.contains("+") &&
                        !et.contains("-") &&
                        !et.contains("×") &&
                        !et.contains("÷") &&
                        et.contains("."))
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                et += "."
                editText.setText(et)
            }
            R.id.button_add -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.' ||
                et[et.length - 1] == '^'
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                et += "+"
                editText.setText(et)
            }
            R.id.button_sub -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.'  ||
                et[et.length - 1] == '^'
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                et += "-"
                editText.setText(et)
            }
            R.id.button_mul -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.' ||
                et[et.length - 1] == '^'
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                et += "×"
                editText.setText(et)
            }
            R.id.button_div -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '.' ||
                et[et.length - 1] == '^'
            ) {
                Toast.makeText(this@Calculator,
                    "Bad Input!",
                    Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                et += "÷"
                editText.setText(et)
            }
            R.id.button_del -> {
                et = if (et.length > 1) {
                    if (et.length == 2 && et[0] == '-') {
                        "0"
                    } else et.substring(0, et.length - 1)
                } else {
                    "0"
                }
                editText.setText(et)
            }
            R.id.button_c -> {
                et = "0"
                editText.setText(et)
            }
            R.id.button_equ -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '^') {
                Toast.makeText(this@Calculator, "Please complete the formula!", Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                val res = getResult()
                if (res.contains("Infinity")) {
                    Toast.makeText(
                        this@Calculator,
                        "0 cannot be used as a divior!",
                        Toast.LENGTH_SHORT
                    ).show()
                    editText.setText("0")
                } else {
                    editText.setText(res)
                }
            }
//            R.id.button_pc -> {
//                var per = et.toDouble()
//                per = per / 100
//                var per1 = "" + per
//                per1 = per1.replace("0+?$".toRegex(), "")
//                per1 = per1.replace("[.]$".toRegex(), "")
//                editText.setText(per1)
//            }

            R.id.button_pc -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '^') {
                Toast.makeText(this@Calculator, "Please complete the formula!", Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                val res = getResult()
                if (res.contains("Infinity")) { Toast.makeText(this@Calculator, "0 cannot be used as a divior!", Toast.LENGTH_SHORT).show()
                    editText.setText("0")
                } else {
                    var per = res.toDouble()
                    per = per / 100
                    var x2 = formatResult(per)
                    editText.setText(x2)
                }
            }

            R.id.button_neg -> if (et[0] >= '0' && et[0] <= '9') {
                if (et == "0") {
                    editText.setText("0")
                } else {
                    editText.setText("-$et")
                }
            } else if (et[0] == '-') editText.setText(
                et.substring(1, et.length)
            ) else editText.setText(et)
            R.id.button_fac -> if (et.contains(".")) {
                Toast.makeText(this@Calculator,
                    "Not integer!",
                    Toast.LENGTH_SHORT).show()
            } else if (et[0] == '-') {
                Toast.makeText(this@Calculator,
                    "Not positive!",
                    Toast.LENGTH_SHORT).show()
            } else {
                if (et == "0") {
                    et = "1"
                    editText.setText(et)
                } else {
                    val num = et.toInt().toDouble()
                    var result = 1.0
                    var i = 1
                    while (i <= num) {
                        result = result * i
                        i++
                    }
                    et = result.toString()
                    editText.setText(et)
                }
            }
//            R.id.button_root -> if (et[0] == '-') {
//                Toast.makeText(this@Calculator, "根号下不能负数", Toast.LENGTH_SHORT).show()
//                editText.setText("0")
//           } else if (et[et.length - 1] == '+' ||
//                et[et.length - 1] == '-' ||
//                et[et.length - 1] == '×' ||
//                et[et.length - 1] == '÷' ||
//                et[et.length - 1] == '^') {
//                Toast.makeText(this@Calculator, "请输入正确格式!", Toast.LENGTH_SHORT).show()
//                editText.setText(et)
//            } else {
//                val res = getResult()
//                var x = et.toDouble()
//                x = Math.sqrt(x)
//                var x2 = formatResult(x)
//                editText.setText(x2)
//            }
            R.id.button_root -> if (et[et.length - 1] == '+' ||
                et[et.length - 1] == '-' ||
                et[et.length - 1] == '×' ||
                et[et.length - 1] == '÷' ||
                et[et.length - 1] == '^') {
                Toast.makeText(this@Calculator, "请输入正确格式！", Toast.LENGTH_SHORT).show()
                editText.setText(et)
            } else {
                val res = getResult()
                var x = res.toDouble()
                if (res.contains("Infinity")) {
                    Toast.makeText(
                        this@Calculator,
                        "0 cannot be used as a divior!",
                        Toast.LENGTH_SHORT
                    ).show()
                    editText.setText("0")
                } else {
                    x = Math.sqrt(x)
                    var res = formatResult(x)
                    if (res.contains("NaN")) {
                        Toast.makeText(this, "根号下不能为负数", Toast.LENGTH_SHORT).show()
                        editText.setText("0")
                    }else{
                        editText.setText(res)
                    }
                }
            }
            else -> {
                Toast.makeText(this@Calculator,
                    "Unexpected error!",
                    Toast.LENGTH_SHORT)
                    .show()
            }
        }
    }

    fun formatResult(result: Double): String {
        var re = String.format("%.9f", result)
        re = re.replace("0+?$".toRegex(), "")
        re = re.replace("[.]$".toRegex(), "")
        return re
    }

    fun getResult(): String {
        val infix = editText.getText().toString()   //计算器中输入的值
        val postfix = toPostfix(infix)              //转后缀
        val result = toValue(postfix)               //通过后缀表达式计算出结果
        var re = formatResult(result)
        return re
    }

    /**
     * 转后缀
     * infix：中缀表达式
     * postfix：字符串 存后缀表达式
     * stack：栈 存放操作符
     */
    fun toPostfix(infix: String): StringBuffer {
        Log.i("infix",infix)
        val stack = Stack<String>()     //定义堆栈，存放操作符
        val postfix = StringBuffer(infix.length * 2)    //定义可变字符串，长度为：infix.length * 2，存后缀表达式
        var i = 0

        //对表达式进行循环
        while (i < infix.length) {
            var ch = infix.get(i)   //算式中第i个字符
            when (ch) {             //判断字符
                //为“+”时
                '+' -> {
                    while (!stack.isEmpty() && stack.peek() != "(")     //栈不空 且 栈顶不等于“（”时
                        postfix.append(stack.pop())                     //出栈，取出栈顶的值 并 附加到postfix字符串中
                    stack.push(ch.toString() + "")               //入栈，把ch的值压入栈顶
                    i++
                }

                //为“-”时
                '-' -> if (i == 0) {        //当第一个字符为负号时，比如-6
                    postfix.append(0)       //postfix字符串后追加0
                    postfix.append(" ")     //postfix可变字符串后缀加 “ ”，操作数之间用空格间隔
                    stack.push("(")  //把左括号 入栈
                    stack.push(ch.toString() + "")  //把“-”入栈
                    i++
                } else {        //“-”不在第一个（不是负数），比如10-8
                    while (!stack.isEmpty() && stack.peek() != "(")     //栈不空，栈顶不等于（时
                        postfix.append(stack.pop())                     //把栈中的所有操作符 缀加到postfix字符串中
                    stack.push(ch.toString() + "")               //把“-”入栈
                    i++
                }

                //为“^”时
//                '^' -> {
//                    //当栈不空，且栈顶等于×、÷、^时，循环
//                    while (!stack.isEmpty() && (stack.peek() == "^"))
//                        postfix.append(stack.pop())         //把栈中的所有操作符 缀加到postfix字符串中
//                    stack.push(ch.toString() + "")   //把对应的操作符，入栈
//                    i++
//                }
                //为‘乘、除、次方时’
                '×', '÷' -> {
                    //当栈不空，且栈顶等于×、÷、^时，循环
                    while (!stack.isEmpty() && (stack.peek() == "×" || stack.peek() == "÷" ))
                        postfix.append(stack.pop())         //把栈中的所有操作符 缀加到postfix字符串中
                    stack.push(ch.toString() + "")   //把对应的操作符，入栈
                    i++
                }

                //为数字时
                else -> if (i == 1 && infix.get(0) == '-') {    //第一个操作数为 负数时   //-32+9
                    //当算式中的字符是数字（小数或整数）时循环；为运算符时退出循环
                    while (i < infix.length && ch >= '0' && ch <= '9' || i < infix.length && ch == '.') {
                        postfix.append(ch)      //把数字 追加到postfix可变字符串
                        i++         //i+1
                        if (i < infix.length)
                            ch = infix.get(i)   //获取算式中的每个字符
                    }
                    //一个操作数 存完后
                    postfix.append(" ")         //往postfix可变字符串后缀加 “ ”，操作数之间用空格间隔
                    postfix.append('-')         //往postfix可变字符串后缀加 “-”
                    stack.pop()                 //出栈
                    stack.pop()                 //出栈
                } else {        //为正数
                    //当算式中的字符是数字（小数或整数）时循环；为运算符时退出循环
                    while (i < infix.length  && ch >= '0' && ch <= '9' || i < infix.length && ch == '.') {
                        postfix.append(ch)     //把数字 追加到postfix可变字符串
                        i++
                        if (i < infix.length)   //循环中缀表达式
                            ch = infix.get(i)   //获取算式中的字符
                    }

                    postfix.append(" ")         //postfix可变字符串后缀加 “ ”，操作数之间用空格间隔
                }
            }
        }

        while (!stack.isEmpty())        //栈不空
            postfix.append(stack.pop()) //把栈中的所有操作符 缀加到postfix字符串中
        return postfix                  //返回后缀表达式postfix
    }

    /**
     * 处理结果值
     * postfix：后缀表达式字符串
     * stack：栈，存放操作数
     */
    fun toValue(postfix: StringBuffer): Double {
        Log.i("postfix", postfix.toString())
        val stack = Stack<Double>()     //定义栈，用于存放操作数
        var value = 0.0                 //存放临时结果
        var j = 0
        var i = 0
        while (i < postfix.length) {    //遍历后缀表达式
            j = i
            var ch = postfix.get(i)     //取第i个字符

            //如果为数字时（包括小数）
            if (ch >= '0' && ch <= '9' || ch == '.') {
                value = 0.0
                //ch不为空时，循环
                while (ch != ' ') {
                    //ch不为空 且 不为‘.’时（整数），循环
                    while (ch != ' ' && ch != '.') {
                        value = value * 10.0 + (ch - '0').toDouble()    //将数字字符，转换为double类型的数。为了计算整数部分的值
                        j++     //代表整数部分的位数
                        ch = postfix.get(++i)       //获取下一个数
                    }

                    //存在小数时
                    if (ch != ' ' && ch == '.')
                        ch = postfix.get(++i)       //获取下一个数


                    while (ch != ' ' && i >= j + 1) {
                        //BigDecimal 类,用于高精度计算
                        val valueBD = BigDecimal(value.toString())      //取整数部分
                        val chBD = BigDecimal(ch - '0')            //取小数部分
                        val nBD = BigDecimal(Math.pow(10.0, (i - j).toDouble()))    //确定'.'后的位数，为了后续计算小数部分
                        val temp = chBD.divide(nBD)                     //相除，chBD÷nBD。计算出小数的值（0.xx）
                        value = valueBD.add(temp).toDouble()            //相加，整数+小数。计算出操作数。如（40+0.3=40.3）
                        ch = postfix.get(++i)                           //获取下一个数
                    }
                    stack.push(value)                                   //每个操作数值 value入栈
                }
            } else {    //为运算符时
                if (ch != ' ') {    //ch不为空
                    var y: Double = stack.pop()     //出栈，第二个操作数->y
                    var x: Double = stack.pop()     //出栈，第二个操作数->x
                    value = when (ch) {             //判断运算符，根据运算符进行运算，结果->value
                        '+' -> x + y
                        '-' -> x - y
                        '×' -> x * y
                        '÷' -> x / y
                        //'^' -> pow(x, 2.0)             //代表x的y次方
                        else -> 0.0
                    }
                    stack.push(value)               //将结果值入栈
                }
            }
            i++
        }
        return stack.pop()
    }

    /**
     * 创建菜单项
     */
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        //绑定菜单项
        //nflate():参数1-通过哪个资源创建菜单      参数2-指定菜单项添加到哪一个Menu对象中
        menuInflater.inflate(R.menu.main,menu)
        return true
    }

    /**
     * 菜单项的点击事件
     */
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            //点击访问主页时
            R.id.visit_item -> {
                Toast.makeText(this, "你点击了访问主页", Toast.LENGTH_SHORT).show()
//                //销毁当前Activity
//                finish()
                //隐式Intent启动浏览器（百度）
                val intent = Intent(Intent.ACTION_VIEW)
                intent.data = Uri.parse("https://gitee.com/jrCnc/caluculator")
                startActivity(intent)
            }

            //点击退出时
            R.id.quit_item -> {
                Toast.makeText(this, "你点击了退出", Toast.LENGTH_SHORT).show()
                //销毁全部Activity
                ActivityCollector.finishAll()

            }
        }
        return true
    }

}